/**
 * 
 */
package com.ffcs.crmd.tsp.server.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ffcs.crmd.tsp.api.dto.job.TspJobDetailShell;
import com.ffcs.crmd.tsp.api.dto.job.TspJobExecutionContext;
import com.ffcs.crmd.tsp.api.dto.netty.RemotingCommand;
import com.ffcs.crmd.tsp.api.dto.task.PriorityWeight;
import com.ffcs.crmd.tsp.api.dto.task.TspJobInstance;
import com.ffcs.crmd.tsp.common.constant.LoggerName;
import com.ffcs.crmd.tsp.common.constant.TspAppConstant;
import com.ffcs.crmd.tsp.core.util.BeanUtils;
import com.ffcs.crmd.tsp.core.util.MixAll;
import com.ffcs.crmd.tsp.core.util.XmlUtil;
import com.ffcs.crmd.tsp.server.jdbc.entity.TaskIdentity;
import com.ffcs.crmd.tsp.server.job.info.JobDetailShell;
import com.ffcs.crmd.tsp.server.netty.task.TaskRegisterInfo;

import io.netty.channel.Channel;

/**
 * 功能说明:
 *
 * @author FFCS-ZHONGFUHUA
 * 
 * @since 
 *
 */
public class PublicMethodHelper {
    /**
     * 日志
     */
    private final static Logger      LOG                 = LoggerFactory.getLogger(LoggerName.ServerLoggerName);
    
    /**
     * 
     * 功能说明:打印对象属性配置
     * 
     * @author ZHONGFUHUA
     *
     * @Date 2016年3月24日
     *
     */
    public static void printObjectProperties(final Logger log, final Object object) {
        printObjectProperties(log, object, false);
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param log
     * @param object
     * @param onlyImportantField
     */
    public static void printObjectProperties(final Logger log, final Object object, final boolean onlyImportantField) {
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (!Modifier.isStatic(field.getModifiers())) {
                String name = field.getName();
                if (!name.startsWith("this")) {
                    Object value = null;
                    try {
                        field.setAccessible(true);
                        value = field.get(object);
                        if (null == value) {
                            value = "";
                        }
                    } catch (IllegalArgumentException e) {
                        System.out.printf(e.getMessage());
                    } catch (IllegalAccessException e) {
                        System.out.printf(e.getMessage());
                    }
                    
                    if (log != null) {
                        log.info(name + "=" + value);
                    } else {
                        System.out.printf(name + "=" + value);
                    }
                }
            }
        }
    }

    /**
     * 
     * 功能说明:
     * 
     * @param taskRegisterInfo
     * @return
     */
    public static boolean validateOldVersion(TaskRegisterInfo taskRegisterInfo) {
        if (taskRegisterInfo != null && StringUtils.isNoneBlank(taskRegisterInfo.getVersion())) {
            return false;
        }
        return true;
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param channel
     * @return
     */
    public static boolean validateChannel(Channel channel) {
        if (channel != null && channel.isActive()) {
            return true;
        }
        return false;
    }
    
    /**
     * 
     * 功能说明:获取任务线程优先级权重配置信息
     * 
     * @param taskIdentity
     * @return
     */
    public static PriorityWeight getThreadPriorityWeight(TaskIdentity taskIdentity){
        try{
            PriorityWeight priorityWeight = new PriorityWeight();
            Map<Integer, Integer> threadPrirorityWeightMap = new HashMap<Integer, Integer>();
            String threadPriorityWeightValue = taskIdentity.getThreadPriorityWeight();
            if (StringUtils.isNoneBlank(threadPriorityWeightValue)) {
                String[] threadPriorityWeights = threadPriorityWeightValue.split(";");
                if (threadPriorityWeights.length > 0) {
                    for (String threadPriorityWeight : threadPriorityWeights) {
                        String[] threadPriorityWeightAttrs = threadPriorityWeight.split(":");
                        if (threadPriorityWeightAttrs.length == 2) {
                            int priority = Integer.valueOf(threadPriorityWeightAttrs[0]);
                            int weight = Integer.valueOf(threadPriorityWeightAttrs[1]);
                            threadPrirorityWeightMap.put(priority, weight);
                        }
                    }
                }
            }
            
            if(MapUtils.isNotEmpty(threadPrirorityWeightMap)){
                Iterator<Entry<Integer, Integer>> threadPriorityWeightIt = threadPrirorityWeightMap.entrySet().iterator();
                while (threadPriorityWeightIt.hasNext()) {
                    Entry<Integer, Integer> entry = threadPriorityWeightIt.next();
                    Integer priority = entry.getKey();
                    Integer weight = entry.getValue();
                    if (weight > 0) {
                        priorityWeight.setPriorityWeight(priority, weight);
                    }
                }
                return priorityWeight;
            }
        }catch(Exception e){
            LOG.error("SERVER-SCHEDULER: get thread priority weight exceptiion:", e);
        }
        return null;
    }
    
    /**
     * 
     * 功能说明:获取任务批量业务数据线程优先级权重配置信息
     * 
     * @param taskIdentity
     * @return
     */
    public static PriorityWeight getBacthThreadPriorityWeight(TaskIdentity taskIdentity){
        try{
            PriorityWeight priorityWeight = new PriorityWeight();
            Map<Integer, Integer> batchThreadPrirorityWeightMap = new HashMap<Integer, Integer>();
            String batchThreadPriorityWeightValue = taskIdentity.getBatchThreadPriorityWeight();
            if (StringUtils.isNoneBlank(batchThreadPriorityWeightValue)) {
                String[] batchThreadPriorityWeights = batchThreadPriorityWeightValue.split(";");
                if (batchThreadPriorityWeights.length > 0) {
                    for (String batchThreadPriorityWeight : batchThreadPriorityWeights) {
                        String[] batchThreadPriorityWeightAttrs = batchThreadPriorityWeight.split(":");
                        if (batchThreadPriorityWeightAttrs.length == 2) {
                            int priority = Integer.valueOf(batchThreadPriorityWeightAttrs[0]);
                            int weight = Integer.valueOf(batchThreadPriorityWeightAttrs[1]);
                            batchThreadPrirorityWeightMap.put(priority, weight);
                        }
                    }
                }
            }
            
            if(MapUtils.isNotEmpty(batchThreadPrirorityWeightMap)){
                Iterator<Entry<Integer, Integer>> businessThreadPriorityWeightIt = batchThreadPrirorityWeightMap.entrySet().iterator();
                while (businessThreadPriorityWeightIt.hasNext()) {
                    Entry<Integer, Integer> entry = businessThreadPriorityWeightIt.next();
                    Integer priority = entry.getKey();
                    Integer weight = entry.getValue();
                    if (weight > 0) {
                        priorityWeight.setPriorityWeight(priority, weight);
                    }
                }
                return priorityWeight;
            }
        }catch(Exception e){
            LOG.error("SERVER-SCHEDULER: get batch thread priority weight exceptiion:", e);
        }
        return null;
    }
    
    
    /**
     * 
     * 功能说明:
     * 
     * @param jobDetailShell
     * @param requestCode
     * @return
     */
    public static  RemotingCommand createShellCommand(JobDetailShell jobDetailShell, int requestCode) {
        TspJobInstance tspJobInstance = jobDetailShell.getContext().getTspJobInstance();
        RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(requestCode);
        TspJobDetailShell tspJobDetailShell = new TspJobDetailShell();
        tspJobDetailShell.setPriority(tspJobInstance.getPriority());
        tspJobDetailShell.setId(jobDetailShell.getId());
        tspJobDetailShell.setContext(jobDetailShell.getContext());
        remotingCommand.setBody(XmlUtil.toXml(tspJobDetailShell).getBytes());
        return remotingCommand;
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param jobDetailShell
     * @param requestCode
     * @return
     */
    @SuppressWarnings("deprecation")
    public static  RemotingCommand createShellCommandOld(JobDetailShell jobDetailShell, int requestCode) {
        TspJobInstance tspJobInstance = jobDetailShell.getContext().getTspJobInstance();
        RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(requestCode);
        TspJobExecutionContext<Object> tspJobExecutionContext = (TspJobExecutionContext<Object>) jobDetailShell.getContext();
        com.ffcs.crmd.tsp.core.job.TspJobExecutionContext<Object> tspJobExecutionContextOld = new com.ffcs.crmd.tsp.core.job.TspJobExecutionContext<Object>();
        tspJobExecutionContextOld.setFireInstanceId(tspJobExecutionContext.getFireInstanceId());
        tspJobExecutionContextOld.setFireTime(tspJobExecutionContext.getFireTime());
        tspJobExecutionContextOld.setJobRunTime(tspJobExecutionContext.getJobRunTime());
        tspJobExecutionContextOld.setNextFireTime(tspJobExecutionContext.getNextFireTime());
        tspJobExecutionContextOld.setPreviousFireTime(tspJobExecutionContext.getPreviousFireTime());
        tspJobExecutionContextOld.setRecovering(tspJobExecutionContext.isRecovering());
        tspJobExecutionContextOld.setRefireCount(tspJobExecutionContext.getRefireCount());
        tspJobExecutionContextOld.setScheduledFireTime(tspJobExecutionContext.getScheduledFireTime());
        
        if (tspJobExecutionContext.getTspJobDataMap() != null) {
            tspJobExecutionContextOld.getTspJobDataMap().putAll(tspJobExecutionContext.getTspJobDataMap().getMap());
            if(tspJobExecutionContext.getTspJobDataMap().get(TspAppConstant.TSP_PARAM_SLICE_GROUP) != null){
                String slices = String.valueOf(tspJobExecutionContext.getTspJobDataMap().get(TspAppConstant.TSP_PARAM_SLICE_GROUP));
                tspJobExecutionContextOld.setSlices(slices.split(","));
            }else if(tspJobExecutionContext.getTspJobDataMap().get(TspAppConstant.TSP_PARAM_SLICES) != null){
                String slices = String.valueOf(tspJobExecutionContext.getTspJobDataMap().get(TspAppConstant.TSP_PARAM_SLICES));
                tspJobExecutionContextOld.setSlices(slices.split(","));
            }
        }
        
        com.ffcs.crmd.tsp.common.job.entity.TspJobDetail tspJobDetailOld = new com.ffcs.crmd.tsp.common.job.entity.TspJobDetail();
        try {
            BeanUtils.applyIf(tspJobDetailOld, tspJobInstance);
            tspJobDetailOld.setGroup(tspJobInstance.getJobName());
        } catch (Exception e) {
            LOG.error("SERVER-SCHEDULER: copy new tspJobDetail entity to tspJobDetailOld exception:", e);
        }
        
        tspJobExecutionContextOld.setTspJobDetail(tspJobDetailOld);
        remotingCommand.setBody(XmlUtil.toXml(tspJobExecutionContextOld).getBytes());
        return remotingCommand;
    }
    
    /**
     * 
     * 功能说明:将Properties中的值写入Object
     * 
     * @param p
     * @param object
     * @throws Throwable
     */
    public static void properties2Object(final Properties p, final Object object) throws Throwable {
        Method[] methods = object.getClass().getMethods();
        for (Method method : methods) {
            String mn = method.getName();
            if (mn.startsWith("set")) {
                try {
                    String tmp = mn.substring(4);
                    String first = mn.substring(3, 4);
                    
                    String key = first.toLowerCase() + tmp;
                    String property = p.getProperty(key);
                    if (property != null) {
                        Class<?>[] pt = method.getParameterTypes();
                        if (pt != null && pt.length > 0) {
                            String cn = pt[0].getSimpleName();
                            Object arg = null;
                            if (cn.equals("int")) {
                                arg = Integer.parseInt(property);
                            } else if (cn.equals("long")) {
                                arg = Long.parseLong(property);
                            } else if (cn.equals("double")) {
                                arg = Double.parseDouble(property);
                            } else if (cn.equals("float")) {
                                arg = Float.parseFloat(property);
                            } else if (cn.equals("boolean")) {
                                arg = Boolean.parseBoolean(property);
                            } else if (cn.equals("String")) {
                                arg = property;
                            } else {
                                continue;
                            }
                            method.invoke(object, new Object[] {arg });
                        }
                    }
                } catch (Throwable e) {
                    throw e;
                }
            }
        }
    }

    /**
     * 
     * 功能说明:
     * 
     * @param orig
     * @param dest
     * @throws Throwable
     */
    public static void propertiesCopy(final Properties orig, final Properties dest) throws Throwable {
        Iterator<Entry<Object, Object>> it = orig.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Object, Object> entry = it.next();
            dest.put(entry.getKey(), entry.getValue());
        }
    }
    
    
    public static Properties getPropertiesQuartz(Properties props) throws Throwable {
        Properties quartzProperties = new Properties();
        propertiesCopy(props, quartzProperties);
        quartzProperties.setProperty(MixAll.TSP_QUARTZ_JOBSTORE_CLASS, "org.quartz.simpl.RAMJobStore");
        quartzProperties.setProperty(MixAll.TSP_QUARTZ_SCHEDULER_THREADNAME, "tsp");
        if (quartzProperties.getProperty(MixAll.TSP_QUARTZ_THREAD_POOL_COUNT) == null) {
            quartzProperties.setProperty(MixAll.TSP_QUARTZ_THREAD_POOL_COUNT, "1");
        }
        return quartzProperties;
    }
    
    public static Properties getProperties(Properties props, String prefix) throws Throwable {
        Properties jdbcProperties = new Properties();
        Enumeration<?> keys = props.propertyNames();

        if (!prefix.endsWith(".")) {
            prefix += ".";
        }

        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            if (key.startsWith(prefix)) {
                String value = props.getProperty(key, "");
                jdbcProperties.put(key.substring(prefix.length()), value);
            }
        }
        return jdbcProperties;
    }

    /**
     * 
     * 功能说明:
     * 
     * @param code
     * @return
     */
    public static String getTimeoutPolicy(Short code) {
        switch (code) {
            case 0:
                return "0:忽略";
            case 1:
                return "1:转移";
            case 2:
                return "2:强制转移";
        }
        return null;
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param pageNumber
     * @param pageSize
     * @return
     */
    public static boolean isQueryPage(Integer pageNumber, Integer pageSize){
        if(pageNumber != null && pageSize != null){
            return true;
        }
        return false;
    }
}
